package com.proxy.server;
import com.proxy.common.codec.ProxyMessageDecoder;
import com.proxy.common.codec.ProxyMessageEncoder;
import com.proxy.common.entity.ClientNode;
import com.proxy.common.entity.ProxyRealServer;
import com.proxy.common.protocol.CommonConstant;
import com.proxy.server.handler.HeartBeatRespHandler;
import com.proxy.server.handler.LoginAuthRespHandler;
import com.proxy.server.handler.ServerChannelHandler;
import com.proxy.server.service.LogBackConfigLoader;
import com.proxy.server.service.ServerBeanManager;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

public class ProxyServer {


    private static Logger logger = LoggerFactory.getLogger(ProxyServer.class);

    /**
     * 最大帧长度
     */
    private static final int MAX_FRAME_LENGTH = 2 * 1024 * 1024;

    /**
     * 长度域偏移
     */
    private static final int LENGTH_FIELD_OFFSET = 0;

    /**
     * 长度域字节数
     */
    private static final int LENGTH_FIELD_LENGTH = 4;

    /**
     * 跳过的字节数
     */
    private static final int INITIAL_BYTES_TO_STRIP = 0;

    /**
     * 数据长度修正
     */
    private static final int LENGTH_ADJUSTMENT = 0;



    /**
     * 绑定端口,默认6666
     */
    public int port;

    /**
     * 并发量
     */
    public static  int concurrent = 1000;

    public ProxyServer() {
        this.port = 6666;
    }

    public ProxyServer(int port) {
        this.port = port;
    }


    private  ChannelFuture bind()  {
        EventLoopGroup bossGroup=new NioEventLoopGroup();
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        ServerBootstrap bootstrap=new ServerBootstrap();
        bootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {

                        socketChannel.pipeline().addLast("idleStateHandler", new IdleStateHandler(10*6, 15*6, 20*6));
                        socketChannel.pipeline().addLast(new ProxyMessageDecoder(MAX_FRAME_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_FIELD_LENGTH));
                        socketChannel.pipeline().addLast(new ProxyMessageEncoder());
                        socketChannel.pipeline().addLast(new LoginAuthRespHandler());
                        socketChannel.pipeline().addLast(new HeartBeatRespHandler());
                        socketChannel.pipeline().addLast(new ServerChannelHandler());
                    }
                });
        ServerBeanManager.setBootstrap(bootstrap);
        ChannelFuture future=null;
        try{
            future=bootstrap.bind(port);
            logger.info("服务器监听端口 {}",port);
        }catch (Exception e){
            e.printStackTrace();
        }
        return future;
    }

    public  void start() throws  Exception{

        //读取代理服务配置文件
        ServerBeanManager.getConfigService().readServerConfig();

        if(ServerBeanManager.getConfigService().getConfigure("port")!=null){
            this.port= (int) ServerBeanManager.getConfigService().getConfigure("port");
        }
        if(ServerBeanManager.getConfigService().getConfigure("concurrent")!=null){
            ProxyServer.concurrent = (int)ServerBeanManager.getConfigService().getConfigure("concurrent");
        }

        //根据配置文件启动服务
        ChannelFuture future=bind();

        //读取客户端配置文件

        Map<String,List<Map<String,Object>>> nodes = (Map<String,List<Map<String,Object>>>) ServerBeanManager.getConfigService().getConfigure("client");

        for (Map.Entry<String,List<Map<String,Object>>> m:nodes.entrySet()){
            ClientNode clientNode=new ClientNode();
            clientNode.setClientKey(m.getKey());
            clientNode.setStatus(CommonConstant.ClientStatus.ACTIVE);
//            clientNode.setName(m.get("name"));

            List<Map<String,Object>> reals = m.getValue();

            for (Map<String,Object> real : reals){
                ProxyRealServer proxy=new ProxyRealServer();
                proxy.setClientKey(m.getKey());
                proxy.setRealHost((String) real.get("realhost"));
                proxy.setServerPort((Integer) real.get("serverport"));
                proxy.setRealHostPort((Integer) real.get("realhostport"));
                proxy.setDescription((String) real.get("description"));
                String proxyType= (String) real.get("proxyType");
                if (proxyType.equalsIgnoreCase("http")){
                    proxy.setType(CommonConstant.ProxyType.HTTP);
                }else if(proxyType.equalsIgnoreCase("tcp")){
                    proxy.setType(CommonConstant.ProxyType.TCP);
                }else {
                    continue;
                }
                clientNode.addServerPort2RealServer(proxy.getServerPort(),proxy);
            }
            ServerBeanManager.getProxyService().add(clientNode.getClientKey(), clientNode);
        }
        // 启动转发服务，暂定这样
        ServerBeanManager.getTransferService().start();

        future.channel().closeFuture().sync();
    }

    public static void main(String[] args)throws  Exception{

        //加载日志
        LogBackConfigLoader.load();

        //启动代理
        new ProxyServer().start();
    }

}
